﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json;
using LightCAD.MathLib;

namespace LightCAD.Runtime
{

    public delegate void SelectsChangedEvent(IDocumentEditor sender, SelectedEventArgs args);

    public class SelectedEventArgs:EventArgs
    {
        public bool Selected;
        public List<LcElement> Elements;
    }
    public class DocumentAction
    {
        public DocumentRuntime docRt;

        public event SelectsChangedEvent SelectsChanged;
  
        public Box2 PastingBox { get; set; }
        public List<LcElement> PastingElements { get; set; } = new List<LcElement>();
        public LcElement HoveredElement { get; set; }
        public List<LcElement> SelectedElements { get; } = new List<LcElement>();
        public double DragSelectionX { get; set; }
        public double DragSelectionY { get; set; }

        public DocumentAction(DocumentRuntime docRt)
        {
            this.docRt = docRt;
            CommandCenter.CommonCommandExecute += Instance_CommandExecute;
        }


        public void Instance_CommandExecute(object sender, CommandExecuteEventArgs e)
        {
            switch (e.Command.Name)
            {
                case "COPY": Copy(); e.Result.Success = true; break;
                case "CUT": Cut(); e.Result.Success = true; break;
                case "PASTE": Paste(); e.Result.Success = true; break;
                case "UNDO": Undo(); e.Result.Success = true; break;
                case "REDO": Redo(); e.Result.Success = true; break;
                case "ERASE": this.docRt.Erase(); e.Result.Success = true; break;
                case "SELECTALL": SelectAll(); e.Result.Success = true; break;
            }
        }


        #region Select

        public void SelectElements(IDocumentEditor docEditor, List<LcElement> elements)
        {
            var newSels = new List<LcElement>();
            foreach (var ele in elements)
            {
                //图层关闭元素不可被选中
                if (this.docRt.Document.Layers.Where(x => x.Name == ele.Layer).First().IsOff)
                    continue;
                //图层冻结元素不可被选中
                if (this.docRt.Document.Layers.Where(x => x.Name == ele.Layer).First().IsFrozen)
                    continue;
                //先注释轴网额选中
                if (ele is LcAxisCircle || ele is LcAxisGrid || ele is LcAxisLine)
                    continue;
                if (!ele.IsSelected)
                {
                    ele.IsSelected = true;
                    newSels.Add(ele);
                    SelectedElements.Add(ele);
                }
            }
            if (newSels.Count > 0)
            {
                var e = new SelectedEventArgs() { Selected = true, Elements = newSels };
                SelectsChanged?.Invoke(docEditor, e);
            }
        }
        //private ViewportRuntime VportRt { get { return this.docRt.DrawingEditRt.ActiveViewportRt; } }
       
      
     
      
        /// <summary>
        /// 设置选中元素的Drag状态
        /// </summary>
        /// <param name="dragging"></param>
        public void SetSelectsToDragging(bool dragging)
        {
            foreach (var ele in SelectedElements)
            {
                ele.RtStatus = dragging ? ElementStatus.Dragging : ElementStatus.Normal;
            }
 
        }
        /// <summary>
        /// 清除选中状态
        /// </summary>
        public void ClearSelects()
        {
            int selectedCount = SelectedElements.Count;
            var changeEles = new List<LcElement>();
            foreach (var ele in SelectedElements)
            {
                ele.IsSelected = false;
                changeEles.Add(ele);
            }
            SelectedElements.Clear();
            if (selectedCount > 0)
            {
                SelectsChanged?.Invoke(null,new SelectedEventArgs { Selected=false,Elements= changeEles });
            }
        }
        public void ClearSelects(IDocumentEditor docEditor,List<LcElement> eles)
        {
            var selectedCount = eles.Count;
            var changeEles = new List<LcElement>();
            foreach (var ele in eles)
            {
                ele.IsSelected = false;
                changeEles.Add(ele);
                SelectedElements.Remove(ele);
            }

            if (selectedCount > 0)
            {
                SelectsChanged?.Invoke(docEditor, new SelectedEventArgs { Selected=false,Elements= changeEles });
            }
        }

        #endregion


        #region Hover

        public LcElement HoverSelectElement(ElementSpace container, Vector2 hitPoint, double selectSize)
        {
            if (HoveredElement != null)
            {
                HoveredElement.SetStatus(ElementStatus.Hovered, false);
                HoveredElement = null;
            }
            for (var i = container.Elements.Count - 1; i >= 0; i--)
            {
                var ele = container.Elements[i];
                var testBox = new Box2(new Vector2(hitPoint.X - selectSize, hitPoint.Y - selectSize), selectSize * 2, selectSize * 2);
                var intersected = ele.IntersectWithBox(testBox.ToPolygon());
                if (intersected)
                {
                    ele.SetStatus(ElementStatus.Hovered, true);
                    HoveredElement = ele;
                    return ele;
                }
            }
            return null;
        }

        public void HoverUnselectElement()
        {
            if (HoveredElement != null)
            {
                HoveredElement.SetStatus(ElementStatus.Hovered, false);
                HoveredElement = null;
            }
        }

        #endregion


       

      

        #region Copy/Cust/Paste
        public void Copy()
        {
            if (this.SelectedElements.Count == 0) return;
            var elements = new List<LcElement>();
            var box = new Box2();
            box.MakeEmpty();
            foreach (var element in this.SelectedElements)
            {
                box.Union(element.BoundingBox);
                var copyEle = element.Clone();
                elements.Add(copyEle);
            }

            foreach (var element in elements)
            {
                element.Translate(-box.Min.X, -box.Min.Y);
            }

            var dataObject = AppRuntime.UISystem.NewClipboardDataObject();

            var stream = new MemoryStream();
            var soptions = new JsonSerializerOptions { WriteIndented = false };
            var options = new JsonWriterOptions { Indented = false };
            using (var writer = new Utf8JsonWriter(stream, options))
            {
                writer.WriteStartObject();
                writer.WritePropertyName("Elements");
                writer.WriteStartArray();
                foreach (var element in elements)
                {
                    writer.WriteElementObject(element, soptions);
                }
                writer.WriteEndArray();
                writer.WriteEndObject();
                writer.Flush();
            }
            var json = Encoding.UTF8.GetString(stream.ToArray());

            AppRuntime.UISystem.SetClipboardData(dataObject, "LightCAD_Elements", json);
            AppRuntime.UISystem.SetToClipboard(dataObject);
        }

        internal void Cut()
        {
            if (this.SelectedElements.Count == 0) return;
            Copy();
            DocumentManager.CurrentRecorder.BeginAction("CUT");
            foreach (var element in this.SelectedElements)
            {
                ((element.Parent) as ElementSpace).RemoveElement(element);
            }
            this.ClearSelects();
            DocumentManager.CurrentRecorder.EndAction();
        }
        internal async void Paste()
        {
            CancelAll();
            var data = await AppRuntime.UISystem.GetClipboardData("LightCAD_Elements");
            if (data == null) return;
            var json = (data is String) ? (string)data : Encoding.Unicode.GetString((byte[])data).Trim('\0');
            var jdoc = JsonDocument.Parse(json);
            var jele = jdoc.RootElement;
            var elements = new List<LcElement>();
            var arr=jele.GetProperty("Elements").EnumerateArray().ToArray();
            for(var i=0;i<arr.Length; i++)
            {
               var ele= arr[i].ReadElementObject(this.docRt.Document);
                elements.Add(ele);
            }
            if (elements.Count == 0) return;
            foreach (var element in elements)
            {

                element.Initilize(this.docRt.Document);
                if (element is LcBlockRef)
                {
                    var blockRef = element as LcBlockRef;
                    var blk = this.docRt.Document.Blocks[blockRef.Block.Id];
                    blockRef.Block = blk;
                }
            }
            var box = new Box2();
            box.MakeEmpty();
            foreach (var element in elements)
            {
                box.Union(element.BoundingBox);
            }
            this.PastingBox = box;//用于显示粘贴内容的外框，暂时无用

            this.ClearSelects();
            this.PastingElements = elements;
            //this.docRt.DrawingEditRt.Paste(data).SetStatus(ViewportStatus.Pasting);

        }
        

        #endregion


        #region Mics
        public void CancelAll()
        {
            this.docRt.DocEditors.ForEach(d=>d.CancelAll());
        }
        internal void Undo()
        {
            CancelAll();
            DocumentManager.CurrentRecorder.UndoAction();
        }
        internal void Redo()
        {
            DocumentManager.CurrentRecorder.RedoAction();
        }
        #endregion

        public void SelectAll()
        {
            this.docRt.DocEditors.ForEach(d => d.SelectAll());
        }
    }
}
